// Copyright 2008 web2me.dev
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package net.web2me.parsers;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.xpath.XPathConstants;

import net.web2me.api.AbstractBaseParser;
import net.web2me.api.ParserException;
import net.web2me.api.util.DocumentGenerator;
import net.web2me.api.util.Downloader;
import net.web2me.api.util.SiteStreamGenerator;
import net.web2me.api.util.UtilityException;
import net.web2me.api.util.XPathResolver;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

public class ImageFapParser extends AbstractBaseParser  {
	
	private Logger logger = Logger.getLogger(this.getClass());
	
	private String imageStoreDir = "";
	
	List<String> otherPages = new ArrayList<String>();
	
	List<String> processedPages = new ArrayList<String>();
	
	private boolean firstCall = true;
	
	private String galleryNamePath = "//font[@face]";
	
	private Document document;
	
	public String getImageStoreDir() {
		return imageStoreDir;
	}

	public void setImageStoreDir(String imageStoreDir) {
		this.imageStoreDir = imageStoreDir;
	}

	public void process(String siteStream) throws ParserException {
		logger.info("Parsing ImageFap");
		
		try {
			document = DocumentGenerator.generate( siteStream );
		} catch (Exception e) {
			throw new ParserException(e);
		}
		
		logger.debug("Loading the page links");
		NodeList links = document.getElementsByTagName("a");
		logger.debug(links.getLength() + " links found");
		
		this.setImageStoreDir( buildDestinyDir( getDirName() ) );
		
		List<String> images = new ArrayList<String>();
		
		logger.info("Scanning document for images");
		
		for( int i = 0; i < links.getLength(); i++){
			
			Element link = (Element)links.item(i);
			String href = "";
			
			//Here I check that the link corresponds to a image link and also that
			//is not an absolute link.
			if( ((href = link.getAttribute("href")).indexOf("image.php?id=") > -1) &&
				!((link.getAttribute("href")).indexOf("http://") > -1)){
					images.add(parseImageLink(href));
			}else if ( (href = "http://www.imagefap.com/" + link.getAttribute("href")).indexOf("&page=") > -1 ){
				if( firstCall || !otherPages.contains(href) ){
					if( (	!otherPages.contains(href)) && 
							!(href.indexOf("&page=0") > -1) &&
							!(href.indexOf("fap.to") > -1)){
						logger.debug("Adding page: " + href);
						otherPages.add(href);
					}
				}
			}
		}
		
		Downloader downloader = new Downloader();
		downloader.setDestinyDirectory(imageStoreDir);
		
		logger.debug("Starting threaded downloading");
		Thread imageThread;
		Thread commentsThread;
		
		for(int i = 0; i < images.size(); i++){
			downloader.setUrl(images.get(i));
			
			logger.debug("Adding a new thread");
			
			imageThread = new Thread(downloader, images.get(i));
			imageThread.start();
			
			commentsThread = new Thread(new CommentsHandler(document, imageStoreDir));
			commentsThread.start();
		}
		
		if( firstCall ){
			firstCall = false;
			
			for( String page: otherPages){
				String newPage = "";
				try {
					newPage = SiteStreamGenerator.getStream(page);
				} catch (UtilityException e) {
					throw new ParserException(e);
				}
				
				this.process(newPage);
			}
		}
	}
	
	/**
	 * Stores the given image in the gallery directory
	 * @param imageUrl The URL of the image
	 * @throws ParserException
	 */
	private String parseImageLink(String imageUrl) throws ParserException{
		String url = "";
		
		if(imageUrl.indexOf("http://") > -1 && imageUrl.endsWith(".jpg")){
			return imageUrl;
		}else{
			url = "http://www.imagefap.com/" + imageUrl;
		}
		
		logger.info("Trying to save: " + url);
		
		String imagePage = "";
		try {
			imagePage = SiteStreamGenerator.getStream(url, "welcome=1");
		} catch (UtilityException e) {
			logger.error(e);
		}
		
		//Check if the page is the age confirmation
		if( imagePage.indexOf("ImageFap contains images that may not be suitable for minors") > -1 ){
			logger.info("Entering to the age check page");
			
			Document checkPage = null;
			try {
				checkPage = DocumentGenerator.generate(imagePage);
			} catch (Exception e) {
				throw new ParserException(e);
			}
			
			NodeList links = checkPage.getElementsByTagName("a");
			
			for( int i = 0; i < links.getLength(); i++ ){
				
				Element link = (Element)links.item(i);
				
				if( link.getAttribute("href").indexOf("&check=") > -1){
					String imgUrl = "http://www.imagefap.com/" + link.getAttribute("href");
					try{
						imagePage = SiteStreamGenerator.getStream(imgUrl);
						break;
					}catch(UtilityException e){
						throw new ParserException(e);
					}
				}
			}
		}else{
			logger.info("Avoiding the age check page");
		}
		
		int escapedBegins = imagePage.indexOf("return lD('") + "return lD('".length();
		int escapeEnds = imagePage.indexOf("'", escapedBegins);
		
		String escapedImageLink = imagePage.substring(escapedBegins, escapeEnds);
		byte[] asciiValues = null;
		try {
			asciiValues = escapedImageLink.getBytes("ASCII");
		} catch (UnsupportedEncodingException e1) {
			logger.error("UnsupportedEncodingException caught", e1);
		}
		
		int lastNumber = Integer.valueOf(escapedImageLink.substring(escapedImageLink.length() - 1));
		
		StringBuilder finalLink = new StringBuilder();
		
		for(int i = 0; i < asciiValues.length - 1; i++){
			int tmpNumber = asciiValues[i] - lastNumber;
			char aChar = new Character((char)tmpNumber);
			
			finalLink.append(aChar);
		}

		
		/*
		kwws=22lpdjhv1lpdjhids1frp2lpdjhv2ixoo26;276827686486;1msj3
		
		function lD(s){ 
			var s1=unescape(s.substr(0,s.length-1)); 
			var t=''; 
			
			for(i=0;i<s1.length;i++)
				t+=String.fromCharCode(s1.charCodeAt(i)-s.substr(s.length-1,1)); 
			alert(t);
			return unescape(t); 
		} 
		 */
		
		String link = finalLink.toString();
		
		logger.debug("Final image url: " + link);
		
		return link;
	}
	
	private String getDirName() throws ParserException{
		logger.debug("Calculating the gallery directory name");
		
		XPathResolver resolver = new XPathResolver(galleryNamePath, document);
		
		String galleryName = null;
		try {
			galleryName = (String) resolver.resolve(XPathConstants.STRING);
			
			// Removing dangerous characters
			galleryName = galleryName.replace("/", "_");
			galleryName = galleryName.replace("?", "_");
			galleryName = galleryName.replace(":", "_");
			galleryName = galleryName.replace("#", "_");
		} catch (UtilityException e1) {
			logger.warn("UtilityException caught", e1);
		}
		
		String galleryId = getUrl().toString().replaceAll("\\D", "");
		
		logger.debug("Gallery ID after regex replacing: " + galleryId);
		
		if(galleryName == null || galleryName.equals("")){
			return galleryId;
		}else{
			return galleryName + " (" + galleryId + ")";
		}
	}
	
	private String buildDestinyDir(String dir){
		String tempDir = this.getDir() + "/" + dir;
		File finalDir = new File(tempDir);
		
		if(!finalDir.exists()){
			if(!finalDir.mkdirs()){
				logger.error("The directory " + tempDir + " could not be created");
			}else{
				logger.info("The directory " + tempDir + " has been created");
			}
		}else{
			logger.info("The directory " + tempDir + " already exists");
		}
		
		return tempDir;
	}
	
}
